package com.issc.framework.helper;

import com.issc.framework.annotation.Aspect;
import com.issc.framework.annotation.Service;
import com.issc.framework.proxy.AbstractAspectProxy;
import com.issc.framework.proxy.Proxy;
import com.issc.framework.proxy.ProxyManager;
import com.issc.framework.proxy.TransactionProxy;

import java.lang.annotation.Annotation;
import java.util.*;

public final class AopHelper {

    static {
        try {
            Map<Class<?>, Set<Class<?>>> aspectMap = createProxyMap();
            Map<Class<?>, List<Proxy>> targetMap = createTargetMap(aspectMap);
            for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
                Class<?> targetClass = targetEntry.getKey();
                List<Proxy> proxyList = targetEntry.getValue();
                Object object = ProxyManager.createProxy(targetClass, proxyList);
                BeanHelper.setBean(targetClass, object);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
//
    private static Set<Class<?>> createTargetClassSet(Aspect aspect) throws Exception {
        Set<Class<?>> targetClassSet = new HashSet<>();
        Class<? extends Annotation> annotation = aspect.value();
        if (!annotation.equals(Aspect.class)) {
            targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));
        }
        return targetClassSet;
    }
//
    private static void createAspectMap(Map<Class<?>, Set<Class<?>>> aspectMap) throws Exception {
        //Map<Class<?>, Set<Class<?>>> aspectMap = new HashMap<>();
        Set<Class<?>> aspectClassSet = ClassHelper.getClassSetBySuper(AbstractAspectProxy.class);
        for (Class<?> aspectClass : aspectClassSet) {
            if (aspectClass.isAnnotationPresent(Aspect.class)) {
                Aspect aspect = aspectClass.getAnnotation(Aspect.class);
                Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
                aspectMap.put(aspectClass, targetClassSet);
            }
        }
    }
//
    private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> aspectMap) throws
            Exception {
        Map<Class<?>, List<Proxy>> targetMap = new HashMap<>();
        for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : aspectMap.entrySet()) {
            Class<?> proxyClass = proxyEntry.getKey();
            Set<Class<?>> targetClassSet = proxyEntry.getValue();
            for (Class<?> targetClass : targetClassSet) {
                Proxy proxy = (Proxy) proxyClass.newInstance();
                if (targetMap.containsKey(targetClass)) {
                    targetMap.get(targetClass).add(proxy);
                } else {
                    List<Proxy> proxyList = new ArrayList<>();
                    proxyList.add(proxy);
                    targetMap.put(targetClass, proxyList);
                }
            }
        }
        return targetMap;
    }
    private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception {
        Map<Class<?>, Set<Class<?>>> classSetMap = new HashMap<>();
        createAspectMap(classSetMap);
        createTransactionMap(classSetMap);
        return classSetMap;
    }

    private static void createTransactionMap(Map<Class<?>, Set<Class<?>>> classSetMap) {
        Set<Class<?>> classSet = ClassHelper.getClassSetByAnnotation(Service.class);
        classSetMap.put(TransactionProxy.class, classSet);
    }
}
